package system

import (
	"encoding/base64"
	"encoding/json"
	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis/v8"
	"io/ioutil"
	"net/http"
	"server/global"
	"server/model/common/response"
	sysModel "server/model/system"
	sysRequest "server/model/system/request"
	sysResponse "server/model/system/response"
	sysService "server/service/system"
	"strconv"
)

type BaseApi struct {
}

func (b *BaseApi) Login(c *gin.Context) {
	l := &sysRequest.Login{}
	if err := c.ShouldBind(l); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	//解密前端base64加密密码
	decodePassword, err := base64.StdEncoding.DecodeString(l.Password)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	l.Password = string(decodePassword)
	if sysService.CaptchaServiceApp.Verify(l.CaptchaId, l.Captcha, true) == false {
		response.FailWithMessage("验证码错误", c)
		return
	}
	user, err := sysService.UserServiceApp.Login(l)
	if err != nil {
		response.FailWithMessage("用户名不存在或者密码错误:"+err.Error(), c)
		return
	}
	var claims = sysService.SysJwtApp.CreateClaims(sysService.BaseClaims{
		UUID:  user.UUID,
		ID:    user.ID,
		Email: user.Email,
		Name:  user.Name,
	})
	token, err := sysService.SysJwtApp.CreateToken(claims)
	c.Set("claims", &claims)
	if err != nil {
		response.FailWithMessage("获取token失败", c)
		return
	}
	//非多点登录
	if !global.GvaConfig.System.UseMultipoint {
		response.OkWithDetailed(sysResponse.LoginResponse{
			User:      *user,
			Token:     token,
			ExpiresAt: claims.StandardClaims.ExpiresAt * 1000,
		}, "登录成功", c)
		return
	}
	//多点登录
	if err, jwtStr := sysService.SysJwtApp.GetRedisJWT(user.UUID.String()); err == redis.Nil {
		if err := sysService.SysJwtApp.SetRedisJWT(token, user.UUID.String()); err != nil {
			response.FailWithMessage("设置登录状态失败", c)
			return
		}
		response.OkWithDetailed(sysResponse.LoginResponse{
			User:      *user,
			Token:     token,
			ExpiresAt: claims.StandardClaims.ExpiresAt * 1000,
		}, "登录成功", c)
	} else if err != nil {
		response.FailWithMessage("设置登录状态失败", c)
	} else {
		var blackJWT sysModel.SysJwtBlacklist
		blackJWT.Jwt = jwtStr
		//旧的token废除
		if err := sysService.SysJwtApp.JsonInBlacklist(blackJWT); err != nil {
			response.FailWithMessage("jwt作废失败", c)
			return
		}
		//存储新的token
		if err := sysService.SysJwtApp.SetRedisJWT(token, user.UUID.String()); err != nil {
			response.FailWithMessage("设置登录状态失败", c)
			return
		}
		response.OkWithDetailed(sysResponse.LoginResponse{
			User:      *user,
			Token:     token,
			ExpiresAt: claims.StandardClaims.ExpiresAt * 1000,
		}, "登录成功", c)
	}
	return
}

//验证码获取
func (b *BaseApi) Captcha(c *gin.Context) {
	if id, b64s, err := sysService.CaptchaServiceApp.Generate(); err != nil {
		response.FailWithMessage("验证码生成失败"+err.Error(), c)
	} else {
		response.OkWithDetailed(gin.H{
			"CaptchaId":   id,
			"CaptchaPath": b64s,
		}, "验证码获取成功", c)
	}
}

// 用户退出登录
func (b *BaseApi) Logout(c *gin.Context) {
	token := c.Request.Header.Get("x-token")
	if token == "" {
		response.FailWithDetailed(gin.H{"reload": true}, "未登录或非法访问", c)
		return
	}
	err := sysService.SysJwtApp.JsonInBlacklist(sysModel.SysJwtBlacklist{Jwt: token})
	if err != nil {
		response.FailWithMessage("拉黑失败："+err.Error(), c)
		return
	}
	response.OkWithMessage("退出登录成功", c)
}

// 获取用户信息
func (b *BaseApi) UserInfo(c *gin.Context) {
	claims, ok := c.Get("claims")
	if !ok {
		response.FailWithMessage("解析用户token失败", c)
		return
	}
	userClaims := claims.(*sysService.CustomClaims)
	//获取用户信息
	user, err := sysService.UserServiceApp.GetUserById(userClaims.ID)
	if err != nil {
		response.FailWithMessage("获取用户信息失败："+err.Error(), c)
		return
	}
	perms, err := sysService.PermissionServiceApp.GetUserPermStrList(strconv.Itoa(int(user.ID)), "admin")
	if err != nil {
		response.FailWithMessage("获取用户信息权限失败："+err.Error(), c)
		return
	}
	response.OkWithDetailed(gin.H{
		"user":  user,
		"perms": perms,
	}, "获取用户信息成功", c)
}

//更新用户信息
func (b *BaseApi) UserUpdate(c *gin.Context) {
	claims, ok := c.Get("claims")
	if !ok {
		response.FailWithMessage("解析用户token失败", c)
		return
	}
	userClaims := claims.(*sysService.CustomClaims)
	var form *sysRequest.SysUserUpdate
	if err := c.ShouldBind(&form); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	if err := sysService.UserServiceApp.UpdateUser(userClaims.ID, form); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	response.OkWithMessage("更新用户信息成功", c)
}

//更新密码
func (b *BaseApi) UserResetPwd(c *gin.Context) {
	claims, ok := c.Get("claims")
	if !ok {
		response.FailWithMessage("解析用户token失败", c)
		return
	}
	userClaims := claims.(*sysService.CustomClaims)
	var form *sysRequest.ResetPwdRequest
	if err := c.ShouldBind(&form); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	if err := sysService.UserServiceApp.UpdatePwd(userClaims.ID, form); err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	response.OkWithMessage("更新密码成功", c)
}

//获取菜单
func (b *BaseApi) GetMenu(c *gin.Context) {
	claims, ok := c.Get("claims")
	if !ok {
		response.FailWithMessage("解析用户token失败", c)
		return
	}
	userClaims := claims.(*sysService.CustomClaims)
	menus, err := sysService.MenuServiceApp.GetUserMenuList(userClaims.ID, sysService.MENU_GROUP_KEY_ADMIN)
	if err != nil {
		response.FailWithMessage("获取用户菜单失败："+err.Error(), c)
		return
	}
	response.OkWithDetailed(gin.H{
		"menus": menus,
	}, "获取菜单成功", c)
}

// 省市区信息
func (b *BaseApi) Geographic(c *gin.Context) {
	resp, err := http.Get("https://wx.suofeiya.com.cn/new/api/region/getTreeList")
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	var data *sysResponse.ApiGeographic
	json.Unmarshal(body, &data)
	response.OkWithData(data.Data, c)
}
